// https://www.bilibili.com/video/BV1iV411b7L1
// 区分组件是 mount首次渲染， 还是 update更新
let isMount = true;
let workingProgressHook = null;

// 定义fiber数据结构
const fiber = {
  stateNode: App, // stateNode保存着App组件本身
  memoizedState: null, //memoizedState 保存hooks数据
};

// 执行fiber调度
function schedule() {
  workingProgressHook = fiber.memoizedState;
  const app = fiber.stateNode(); //相当于触发组件render，执行App()
  isMount = false; //首次调用之后，状态就是更新
  return app;
}

// 定义useState
function useState(initialState) {
  let hook;
  // 区分首次渲染还是更新
  if (isMount) {
    //挂载
    hook = {
      memoizedState: initialState,
      next: null,
      queue: {
        pending: null,
      },
    };
    if (!fiber.memoizedState) {
      // 第一次调用useState
      fiber.memoizedState = hook;
    } else {
      // 将多次调用的useState的hook进行串连
      workingProgressHook.next = hook;
    }
    workingProgressHook = hook;
  } else {
    // update的过程
    hook = workingProgressHook;
    workingProgressHook = workingProgressHook.next;
  }

  let baseState = hook.memoizedState;
  if (hook.queue.pending) {
    // 第一个update
    let firstUpdate = hook.queue.pending.next;
    do {
      const action = firstUpdate.action; // 传递过来要执行的函数
      baseState = action(baseState);
      firstUpdate = firstUpdate.next;
    } while (firstUpdate !== hook.queue.pending.next);
    hook.queue.pending = null;
  }
  hook.memoizedState = baseState;
  // bind 的第一个参数会作为原函数运行时的 this 指向
  // 第二个开始的参数是可选的，当绑定函数被调用时，这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数
  // 所以会把 updateNum函数内定义的函数作为参数进行传递给函数调用的时候
  return [baseState, dispatchAction.bind(null, hook.queue)];
}

function dispatchAction(queue, action) {
  const update = { action, next: null };
  if (queue.pending === null) { // 还没有链表关系
    // 创建环状链表
    update.next = update;
  } else { //已经调用一次 updateNum 函数，如果后边有多次调用updateNum函数
    // queue.pending 已经存在；update是新插入的；
    // update.next被赋值为queue.pending.next，说明将update.next指向原链表的头，【queue.pending表示尾，.next表示头】
    update.next = queue.pending.next;
    // 更新链表头
    queue.pending.next = update;
  }
  // queue.pending为链表的最后一个update
  queue.pending = update;
  schedule();
}

function App() {
  const [num, updateNum] = useState(0);
  const [numA, updateNumA] = useState(0);
  console.log("isMount", isMount);
  console.log("num", num);
  console.log("numA", numA);
  return {
    onClick() {
      updateNum((num) => num + 1);
    },
    onFocus() {
      updateNumA((num) => num + 10);
    },
  };
}
// 把schedule函数挂载到全局对象window的app属性上，这样可以全局获取到
window.app = schedule();

// 在控制台，通过调用app.onClick 和app.onFocus观察hooks的执行
